package com.uduemc.biso.node.web.component;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

import org.apache.commons.io.FileUtils;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.HttpClients;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.uduemc.biso.core.extities.pojo.DeployType;
import com.uduemc.biso.core.utils.HttpUtil;
import com.uduemc.biso.core.utils.RestResult;
import com.uduemc.biso.node.core.common.utils.AssetsUtil;
import com.uduemc.biso.node.core.property.CenterProperty;
import com.uduemc.biso.node.core.property.GlobalProperties;
import com.uduemc.biso.node.core.utils.SiteUrlUtil;

import lombok.extern.slf4j.Slf4j;

@Component
@Slf4j
public class DeployFunction {

	public static List<String> deploies = new ArrayList<>();
	static {
		deploies.add(DeployType.NODE_BACKEND);
		deploies.add(DeployType.BACKENDJS);
		deploies.add(DeployType.COMPONENTS);
		deploies.add(DeployType.SITEJS);
	}

	@Autowired
	GlobalProperties globalProperties;

	@Autowired
	ObjectMapper objectMapper;

	/**
	 * 通过 deployname 获取其对应的最新的版本号
	 * 
	 * @param deployname
	 * @return
	 */
	public String lastVersion(String deployname) {
		CenterProperty center = globalProperties.getCenter();
		String url = center.getCenterApiHost() + center.getApiDeployLastVersion();
		Map<String, String> param = new HashMap<>();
		param.put("deployname", deployname);
		log.debug("DeployFunction.lastVersion GET请求地址： " + url + " 参数: deployname=" + deployname);
		String response = HttpUtil.get(url, param);
		boolean isMatch = Pattern.matches(DeployType.VERSION_PATTERN, response);
		return isMatch ? response : null;
	}

	/**
	 * 通过 deployname 获取其对应的最新的版本号数据
	 * 
	 * @param deployname
	 * @return
	 * @throws IOException
	 * @throws JsonMappingException
	 * @throws JsonParseException
	 */
	public RestResult lastVersionData(String deployname) throws JsonParseException, JsonMappingException, IOException {
		CenterProperty center = globalProperties.getCenter();
		String url = center.getCenterApiHost() + center.getApiDeployLastVersionData();
		Map<String, String> param = new HashMap<>();
		param.put("deployname", deployname);
		log.debug("DeployFunction.lastVersionData GET请求地址： " + url + " 参数: deployname=" + deployname);
		String response = HttpUtil.get(url, param);
		return objectMapper.readValue(response, RestResult.class);
	}

	/**
	 * 主控端 NODE_BACKEND 最新版本
	 * 
	 * @return
	 * @throws IOException
	 */
	public String lastNodeBackendVersion() throws IOException {
		return lastVersion(DeployType.NODE_BACKEND);
	}

	/**
	 * 主控端 COMPONENTS 最新版本
	 * 
	 * @return
	 * @throws IOException
	 */
	public String lastComponentsVersion() throws IOException {
		return lastVersion(DeployType.COMPONENTS);
	}

	/**
	 * 主控端 BACKENDJS 最新版本
	 * 
	 * @return
	 * @throws IOException
	 */
	public String lastBackendjsVersion() throws IOException {
		return lastVersion(DeployType.BACKENDJS);
	}

	/**
	 * 主控端 SITEJS 最新版本
	 * 
	 * @return
	 * @throws IOException
	 */
	public String lastSitejsVersion() throws IOException {
		return lastVersion(DeployType.SITEJS);
	}

	/**
	 * 通过 deployname 获取本地工程当前的版本号
	 * 
	 * @param deployname
	 * @return
	 * @throws IOException
	 */
	public String localhostVersion(String deployname) throws IOException {
		if (deployname.equals(DeployType.NODE_BACKEND)) {
			return localhostNodeBackendVersion();
		} else if (deployname.equals(DeployType.BACKENDJS)) {
			return localhostBackendjsVersion();
		} else if (deployname.equals(DeployType.COMPONENTS)) {
			return localhostComponentsVersion();
		} else if (deployname.equals(DeployType.SITEJS)) {
			return localhostSitejsVersion();
		} else {
			log.error("未定义的 DeployType ：" + deployname);
		}
		return null;
	}

	/**
	 * 本地 NODE_BACKEND 版本
	 * 
	 * @return
	 * @throws IOException
	 */
	public String localhostNodeBackendVersion() throws IOException {
		String nodeBackendPath = globalProperties.getNode().getNodeBackendPath();
		String nodeBackendVersion = nodeBackendPath + File.separator + "version.txt";
		File nodeBackendFile = new File(nodeBackendVersion);
		if (!nodeBackendFile.isFile()) {
			return null;
		}
		return FileUtils.readFileToString(nodeBackendFile, "UTF-8");
	}

	/**
	 * 写入工程的版本号
	 * 
	 * @param version
	 * @throws IOException
	 */
	public void localhostNodeBackendVersionWrite(String version) throws IOException {
		String nodeBackendPath = globalProperties.getNode().getNodeBackendPath();
		String nodeBackendVersion = nodeBackendPath + File.separator + "version.txt";
		File nodeBackendFile = new File(nodeBackendVersion);
		FileUtils.writeStringToFile(nodeBackendFile, version, "UTF-8");
	}

	/**
	 * 本地 COMPONENTS 版本
	 * 
	 * @return
	 * @throws IOException
	 */
	public String localhostComponentsVersion() throws IOException {
		String componentsPath = AssetsUtil.getComponentsDistPath(globalProperties.getSite().getAssetsPath())
				+ File.separator + "version.txt";
		File componentsFile = new File(componentsPath);
		if (!componentsFile.isFile()) {
			return null;
		}
		return FileUtils.readFileToString(componentsFile, "UTF-8");
	}

	/**
	 * 写入工程的版本号
	 * 
	 * @param version
	 * @throws IOException
	 */
	public void localhostComponentsVersionWrite(String version) throws IOException {
		String componentsPath = AssetsUtil.getComponentsDistPath(globalProperties.getSite().getAssetsPath())
				+ File.separator + "version.txt";
		File componentsFile = new File(componentsPath);
		FileUtils.writeStringToFile(componentsFile, version, "UTF-8");
	}

	/**
	 * 本地 BACKENDJS 版本
	 * 
	 * @return
	 * @throws IOException
	 */
	public String localhostBackendjsVersion() throws IOException {
		String backendjsPath = AssetsUtil.getBackendjsRootPath(globalProperties.getSite().getAssetsPath())
				+ File.separator + "version.txt";
		File backendjsFile = new File(backendjsPath);
		if (!backendjsFile.isFile()) {
			return null;
		}
		return FileUtils.readFileToString(backendjsFile, "UTF-8");
	}

	/**
	 * 写入工程的版本号
	 * 
	 * @param version
	 * @throws IOException
	 */
	public void localhostBackendjsVersionWrite(String version) throws IOException {
		String backendjsPath = AssetsUtil.getBackendjsRootPath(globalProperties.getSite().getAssetsPath())
				+ File.separator + "version.txt";
		File backendjsFile = new File(backendjsPath);
		FileUtils.writeStringToFile(backendjsFile, version, "UTF-8");
	}

	/**
	 * 本地 SITEJS 版本
	 * 
	 * @return
	 * @throws IOException
	 */
	public String localhostSitejsVersion() throws IOException {
		String componentsPath = AssetsUtil.getSitejsRootPath(globalProperties.getSite().getAssetsPath())
				+ File.separator + "version.txt";
		File componentsFile = new File(componentsPath);
		if (!componentsFile.isFile()) {
			return null;
		}
		return FileUtils.readFileToString(componentsFile, "UTF-8");
	}

	/**
	 * 写入工程的版本号
	 * 
	 * @param version
	 * @throws IOException
	 */
	public void localhostSitejsVersionWrite(String version) throws IOException {
		String sitejsPath = AssetsUtil.getSitejsRootPath(globalProperties.getSite().getAssetsPath()) + File.separator
				+ "version.txt";
		File sitejsFile = new File(sitejsPath);
		FileUtils.writeStringToFile(sitejsFile, version, "UTF-8");
	}

	/**
	 * 通过 deployname 下载其对应的最新的版本号的压缩包
	 * 
	 * @param deployname
	 * @return
	 * @throws IOException
	 */
	public String downloadAndZipPath(String deployname) throws IOException {
		if (deployname.equals(DeployType.NODE_BACKEND)) {
			return downloadAndZipPathNodeBackend(lastNodeBackendVersion());
		} else if (deployname.equals(DeployType.BACKENDJS)) {
			return downloadAndZipPathBackendjs(lastBackendjsVersion());
		} else if (deployname.equals(DeployType.COMPONENTS)) {
			return downloadAndZipPathComponents(lastComponentsVersion());
		} else if (deployname.equals(DeployType.SITEJS)) {
			return downloadAndZipPathSitejs(lastSitejsVersion());
		} else {
			log.error("未定义的 DeployType ：" + deployname);
		}
		return null;
	}

	/**
	 * 下载 node-backend 的压缩文件，并且返回下载后的压缩包文件目录
	 * 
	 * @param version
	 * @return
	 * @throws IOException
	 */
	public String downloadAndZipPathNodeBackend(String version) throws IOException {
		String zipPath = makeZipPath(DeployType.NODE_BACKEND, version);
		File file = new File(zipPath);
		if (file.isFile()) {
			return zipPath;
		}
		Map<String, String> params = new HashMap<>();
		params.put("deployname", DeployType.NODE_BACKEND);
		params.put("version", version);

		CenterProperty center = globalProperties.getCenter();
		String url = center.getCenterApiHost() + center.getApiDeployDownload();
		String downloadLink = SiteUrlUtil.appendParams(url, params);
		// 开始进行下载动作
		return downloadByUrl(zipPath, downloadLink);
	}

	/**
	 * 下载 components 的压缩文件，并且返回下载后的压缩包文件目录
	 * 
	 * @param version
	 * @return
	 * @throws IOException
	 */
	public String downloadAndZipPathComponents(String version) throws IOException {
		String zipPath = makeZipPath(DeployType.COMPONENTS, version);
		File file = new File(zipPath);
		if (file.isFile()) {
			return zipPath;
		}
		Map<String, String> params = new HashMap<>();
		params.put("deployname", DeployType.COMPONENTS);
		params.put("version", version);

		CenterProperty center = globalProperties.getCenter();
		String url = center.getCenterApiHost() + center.getApiDeployDownload();
		String downloadLink = SiteUrlUtil.appendParams(url, params);
		// 开始进行下载动作
		return downloadByUrl(zipPath, downloadLink);
	}

	/**
	 * 下载 backendjs 的压缩文件，并且返回下载后的压缩包文件目录
	 * 
	 * @param version
	 * @return
	 * @throws IOException
	 */
	public String downloadAndZipPathBackendjs(String version) throws IOException {
		String zipPath = makeZipPath(DeployType.BACKENDJS, version);
		File file = new File(zipPath);
		if (file.isFile()) {
			return zipPath;
		}
		Map<String, String> params = new HashMap<>();
		params.put("deployname", DeployType.BACKENDJS);
		params.put("version", version);

		CenterProperty center = globalProperties.getCenter();
		String url = center.getCenterApiHost() + center.getApiDeployDownload();
		String downloadLink = SiteUrlUtil.appendParams(url, params);
		// 开始进行下载动作
		return downloadByUrl(zipPath, downloadLink);
	}

	/**
	 * 下载 sitejs 的压缩文件，并且返回下载后的压缩包文件目录
	 * 
	 * @param version
	 * @return
	 * @throws IOException
	 */
	public String downloadAndZipPathSitejs(String version) throws IOException {
		String zipPath = makeZipPath(DeployType.SITEJS, version);
		File file = new File(zipPath);
		if (file.isFile()) {
			return zipPath;
		}
		Map<String, String> params = new HashMap<>();
		params.put("deployname", DeployType.SITEJS);
		params.put("version", version);

		CenterProperty center = globalProperties.getCenter();
		String url = center.getCenterApiHost() + center.getApiDeployDownload();
		String downloadLink = SiteUrlUtil.appendParams(url, params);
		// 开始进行下载动作
		return downloadByUrl(zipPath, downloadLink);
	}

	/**
	 * 通过传入参数，对远程文件进行下载，并保存到对应的文件目录
	 * 
	 * @param zipPath
	 * @param downloadLink
	 * @return
	 * @throws IOException
	 */
	public String downloadByUrl(String zipPath, String downloadLink) throws IOException {
		File file = new File(zipPath);
		if (!file.isFile()) {
			// 进行下载操作
			HttpGet httpGet = new HttpGet(downloadLink);
			HttpClient httpClient = HttpClients.createDefault();

			HttpResponse httpResponse = httpClient.execute(httpGet);
			HttpEntity entity = httpResponse.getEntity();
			Header contentType = entity.getContentType();
			if (contentType == null) {
				log.error("下载模板失败！downloadLink: " + downloadLink);
				return null;
			}
			String value = contentType.getValue();
			if (!value.equals("application/x-download")) {
				log.error("下载模板失败！downloadLink： " + downloadLink);
				return null;
			}
			File parentFile = file.getParentFile();
			if (!parentFile.isDirectory()) {
				FileUtils.forceMkdir(parentFile);
			}
			// 创建并下载
			file.createNewFile();
			try (OutputStream out = new FileOutputStream(file); InputStream in = entity.getContent();) {
				byte[] buffer = new byte[4096];
				int readLength = 0;
				while ((readLength = in.read(buffer)) > 0) {
					byte[] bytes = new byte[readLength];
					System.arraycopy(buffer, 0, bytes, 0, readLength);
					out.write(bytes);
				}
				out.flush();
			}

		}
		if (new File(zipPath).isFile()) {
			return zipPath;
		}
		return null;
	}

	/**
	 * 生产zip压缩文件的保存目录
	 * 
	 * @param deployname
	 * @param version
	 * @return
	 * @throws IOException
	 */
	public String makeZipPath(String deployname, String version) throws IOException {
		String[] split = version.split("\\.");
		String deployPath = globalProperties.getNode().getDeployPath();
		String path = deployPath + File.separator + deployname + File.separator + split[0] + File.separator + deployname
				+ "-" + version + ".zip";
		File file = new File(path);
		if (!file.isFile()) {
			FileUtils.forceMkdir(new File(path).getParentFile());
		}
		return path;
	}
}
